#ifndef MASTER_H_
#define MASTER_H_

#include <map>
#include <set>
#include "DataServer.h"
#include "Signals.h"

class Master {
public:
    Master();
    
    virtual void run();
    virtual void serveBlockInfo();
    
protected:
    class IterationInfo {
    public:
        void initialize(int slaves_count);
        
        void clear();
        static void swapContent(IterationInfo& a, IterationInfo& b);
        ~IterationInfo();
        
        std :: map<int, int> blockToSlave;
        std :: map<int, std :: set<int>* > slaveToBlocks;
    };
    
    class BlockInfoServer : public DataServer {
    public:
        void setBlockInfoSource(IterationInfo* info_source) {
            this -> info_source = info_source;
        }
    
    protected:
        void listenForRequest();
        void sendResponse();
        
        int requested_block_id;
        IterationInfo* info_source;
    };
    
    virtual bool isValidBlock(int block_id);
    virtual void markBlockAsDone(int block_id, int slave_id);
    virtual int chooseNextBlockFor(int idle_slave);
    
    virtual void initializeIteration();
    virtual void assignAllBlocksToSlaves();
    virtual void waitForEndOfComputations();
    virtual void finishIteration();
    
    virtual void broadcastSignal(Signals :: CommunicationSignals signal);
    virtual void sendTerminationSignal();
    virtual void sendNextIterationSignal();
    virtual void sendBlockAssignmentSignal(int block_id, int idle_slave);
    virtual void recieveReadyToWorkSignal(int& block_id, int& idle_slave);
    
    
    int blocks_count, iterations_count, processes_count;
    std :: set<int> todo;
    std :: set<int> in_progress;
    IterationInfo prev_info, current_info;
    BlockInfoServer block_info_server;
    MPI_Request request;
    MPI_Status status;
    int nothing;
};

#endif
